<script lang="ts" setup>
import type { FileUploadItem } from '#/components/FileUploader/types';

import { ref, watch } from 'vue';

import { Close, Upload as UploadIcon } from '@icon-park/vue-next';

import { client, fileTransfer } from '#/api/core/client';
import ErrorBoundary from '#/components/ErrorBoundary/ErrorBoundary.vue';
import { FileDropZone, FileUploadQueue } from '#/components/FileUploader';
import Button from '#/components/fluentui/Button.vue';
import Dialog from '#/components/fluentui/Dialog.vue';
import DialogBody from '#/components/fluentui/DialogBody.vue';

interface Props {
  onUploadSuccess?: (items: FileUploadItem[]) => void;
}

interface ShareInfo {
  shareCode: null | string;
  editToken: null | string | undefined;
  backendId: null | number | undefined;
}

defineProps<Props>();
const emit = defineEmits<{
  close: [];
  isUploadChange: [isUpload: boolean];
  uploadComplete: [
    items: FileUploadItem[],
    averageSpeed?: number,
    shareInfo?: null | ShareInfo,
  ];
}>();
const isOpen = defineModel<boolean>('isOpen', {
  default: false,
});
const isUploading = ref(false);
watch(isUploading, (v) => {
  emit('isUploadChange', v);
});
// 状态管理
const uploadQueue = ref<FileUploadItem[]>([]);
const uploadMessage = ref('');
const currentUploadTasks = new Map<string, AbortController>();

// 上传统计信息
const uploadStats = ref({
  startTime: 0,
  totalBytesUploaded: 0,
  averageSpeed: 0,
});

// 错误处理状态
const errorBoundaryKey = ref(0);

// 生成唯一ID
const generateId = () => {
  return `upload_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
};

// 添加文件到队列
const addFilesToQueue = (files: File[]) => {
  const newItems: FileUploadItem[] = files.map((file) => ({
    id: generateId(),
    name: file.name,
    size: file.size,
    file,
    status: 'pending',
  }));

  // 检查是否有重复文件
  for (const newItem of newItems) {
    const exists = uploadQueue.value.some(
      (item) => item.name === newItem.name && item.size === newItem.size,
    );

    if (!exists) {
      // 检查内存是否足够处理此文件
      // const memoryCheck = MemoryMonitor.canHandleLargeFile(newItem.size);
      // if (!memoryCheck.canHandle) {
      //   console.warn('文件可能过大:', {
      //     fileName: newItem.name,
      //     fileSize: newItem.size,
      //     reason: memoryCheck.reason,
      //     suggestion: memoryCheck.suggestion,
      //   });

      //   // 将文件添加到队列但标记为错误状态
      //   newItem.status = 'error';
      //   newItem.error = `${memoryCheck.reason}: ${memoryCheck.suggestion}`;
      // }

      uploadQueue.value.push(newItem);
    }
  }
};

// 移除文件
const removeItem = (id: string) => {
  if (currentUploadTasks.has(id)) {
    cancelItem(id);
  }
  uploadQueue.value = uploadQueue.value.filter((item) => item.id !== id);
};

// 取消上传
const cancelItem = (id: string) => {
  const controller = currentUploadTasks.get(id);
  if (controller) {
    controller.abort();
    currentUploadTasks.delete(id);
  }

  const item = uploadQueue.value.find((item) => item.id === id);
  if (
    item &&
    (item.status === 'uploading' || item.status === 'calculating-md5')
  ) {
    item.status = 'cancelled';
    item.error = '用户取消上传';
    item.progress = undefined;
    item.md5Progress = undefined;
  }
};

// 清空所有文件
const clearAll = () => {
  for (const [id] of currentUploadTasks) {
    cancelItem(id);
  }
  uploadQueue.value = [];
  isUploading.value = false;
};

// 暂停上传
const pauseUpload = () => {
  isUploading.value = false;
  // 取消所有正在进行的上传
  for (const [id] of currentUploadTasks) {
    cancelItem(id);
  }
};

// 重试上传
const retryItem = (id: string) => {
  if (id === 'all-failed') {
    // 重试所有失败的文件
    const failedItems = uploadQueue.value.filter(
      (item) => item.status === 'error',
    );
    for (const item of failedItems) {
      item.status = 'pending';
      item.error = undefined;
      item.progress = undefined;
    }
    if (!isUploading.value) {
      startUpload();
    }
  } else {
    // 重试单个文件
    const item = uploadQueue.value.find((item) => item.id === id);
    if (item) {
      item.status = 'pending';
      item.error = undefined;
      item.progress = undefined;
      if (!isUploading.value) {
        uploadSingleFile(item);
      }
    }
  }
};

// 上传单个文件
const uploadSingleFile = async (item: FileUploadItem) => {
  if (item.status !== 'pending') return;

  try {
    // 首先设置为MD5计算状态
    item.status = 'calculating-md5';
    item.progress = undefined;
    item.md5Progress = undefined;
    item.error = undefined;

    const controller = new AbortController();
    currentUploadTasks.set(item.id, controller);
    const chunkSize = 10 * 1024 * 1024;
    const uploader = fileTransfer.createUpload(chunkSize);

    const uploadedId = await uploader.uploadFile(item.file, {
      chunkSize,
      onMd5Progress: (processedBytes, totalBytes, percentage) => {
        if (controller.signal.aborted) return;
        item.md5Progress = {
          processedBytes,
          totalBytes,
          percentage,
        };
      },
      onProgress: (progressInfo) => {
        if (controller.signal.aborted) return;
        // MD5计算完成，切换到上传状态
        if (item.status === 'calculating-md5') {
          item.status = 'uploading';
          item.md5Progress = undefined;
        }
        item.progress = progressInfo;
      },
    });

    if (!controller.signal.aborted) {
      item.status = 'success';
      item.uploadedId = uploadedId;
      currentUploadTasks.delete(item.id);
    }
  } catch (error) {
    if (!currentUploadTasks.get(item.id)?.signal.aborted) {
      item.status = 'error';
      item.error = error instanceof Error ? error.message : '上传失败';
      currentUploadTasks.delete(item.id);
    }
  }
};

// 开始上传
const startUpload = async () => {
  if (isUploading.value || uploadQueue.value.length === 0) return;

  const pendingItems = uploadQueue.value.filter(
    (item) => item.status === 'pending',
  );

  if (pendingItems.length === 0) return;

  // 初始化上传统计信息
  uploadStats.value = {
    startTime: Date.now(),
    totalBytesUploaded: 0,
    averageSpeed: 0,
  };

  isUploading.value = true;
  try {
    // 并发上传多个文件（最多3个）
    const maxConcurrent = 3;
    const uploading: Promise<void>[] = [];

    for (const item of pendingItems) {
      if (!isUploading.value) break;

      if (uploading.length >= maxConcurrent) {
        await Promise.race(uploading);
        for (let i = uploading.length - 1; i >= 0; i--) {
          const promise = uploading[i];
          if (
            (await Promise.race([promise, Promise.resolve('pending')])) !==
            'pending'
          ) {
            uploading.splice(i, 1);
          }
        }
      }

      const uploadPromise = uploadSingleFile(item).catch((error) => {
        console.error('上传任务异常:', {
          itemId: item.id,
          fileName: item.name,
          error,
        });
        // 确保不会因为单个文件的错误而导致整个上传流程停止
      });
      uploading.push(uploadPromise);
    }

    await Promise.allSettled(uploading);
  } catch (error) {
    console.error('上传流程发生错误:', error);
  } finally {
    isUploading.value = false;

    const completedItems = uploadQueue.value.filter(
      (item) => item.status === 'success' || item.status === 'error',
    );

    if (completedItems.length === uploadQueue.value.length) {
      // 计算总上传时间和平均速度
      const totalUploadTime = (Date.now() - uploadStats.value.startTime) / 1000; // 转换为秒
      const totalUploadedBytes = completedItems
        .filter((item) => item.status === 'success')
        .reduce((sum, item) => sum + item.size, 0);

      if (totalUploadTime > 0) {
        uploadStats.value.averageSpeed = totalUploadedBytes / totalUploadTime;
      }

      // 获取成功上传的文件
      const successItems = uploadQueue.value.filter(
        (item) => item.status === 'success',
      );

      // 如果有成功上传的文件，创建分享
      if (successItems.length > 0) {
        try {
          const shareInfo = await createShareForUploadedFiles(successItems);
          // 传递分享信息给父组件
          emit(
            'uploadComplete',
            [...uploadQueue.value],
            uploadStats.value.averageSpeed,
            shareInfo, // 传递分享信息
          );
        } catch (error) {
          console.error('创建分享失败:', error);
          // 即使分享创建失败，也要通知上传完成
          emit(
            'uploadComplete',
            [...uploadQueue.value],
            uploadStats.value.averageSpeed,
            null, // 分享创建失败时传递null
          );
        }
      } else {
        // 没有成功文件时也要通知完成
        emit(
          'uploadComplete',
          [...uploadQueue.value],
          uploadStats.value.averageSpeed,
          null,
        );
      }
    }
  }
};

// 取消上传
const handleCancel = () => {
  // 如果正在上传，需要用户确认
  if (isUploading.value) {
    // 这里可以显示一个确认对话框，但为了简化，我们直接取消上传
    console.log('用户取消了正在进行的上传');
  }

  // 取消所有正在进行的上传
  for (const [id] of currentUploadTasks) {
    cancelItem(id);
  }

  emit('close');
};

// 处理上传错误
const handleUploadError = (message: string) => {
  console.error('上传错误:', message);
};

// 重新选择文件
const reselectFiles = () => {
  // 清空当前文件队列
  clearAll();
};

// 重置对话框状态
const resetDialog = () => {
  // 清空所有文件
  clearAll();
  // 清空备注信息
  uploadMessage.value = '';
};

// 为上传成功的文件创建分享
const createShareForUploadedFiles = async (successItems: FileUploadItem[]) => {
  try {
    // 收集文件MD5列表
    const fileMd5List = successItems
      .map((item) => item.uploadedId)
      .filter((x) => x !== undefined);

    if (fileMd5List.length === 0) {
      console.warn('没有有效的文件MD5，无法创建分享');
      return { shareCode: null, editToken: null, backendId: null };
    }

    // 调用创建分享API
    const response = await client.shareItem.createShareItem({
      files: fileMd5List,
    });

    // 获取分享信息
    const shareItem = response.data.shareItem;
    const editToken = response.data.editToken;
    const shareCode = shareItem?.code;
    const backendId = shareItem?.id;

    if (shareCode) {
      // 将分享信息存储到文件项中
      successItems.forEach((item) => {
        item.shareCode = shareCode;
        item.editToken = editToken;
        item.backendId = backendId;
      });

      console.log('分享创建成功:', {
        shareCode,
        editToken,
        backendId,
        fileCount: successItems.length,
      });

      return { shareCode, editToken, backendId };
    } else {
      throw new Error('创建分享成功但未返回分享码');
    }
  } catch (error) {
    console.error('创建分享失败:', {
      error: error instanceof Error ? error.message : String(error),
      stack: error instanceof Error ? error.stack : undefined,
      fileCount: successItems.length,
    });
    throw error;
  }
};

// 暴露方法给父组件
defineExpose({
  resetDialog,
  clearAll,
});

// 错误边界处理
const handleErrorBoundaryError = (error: Error) => {
  console.error('上传对话框发生致命错误:', error);
  // 停止所有上传任务
  for (const [id] of currentUploadTasks) {
    cancelItem(id);
  }
  isUploading.value = false;
};

const handleErrorBoundaryRetry = () => {
  console.log('用户请求重试上传');
  errorBoundaryKey.value += 1;
  // 重置失败的文件状态
  uploadQueue.value.forEach((item) => {
    if (item.status === 'error') {
      item.status = 'pending';
      item.error = undefined;
      item.progress = undefined;
    }
  });
};

const handleErrorBoundaryReset = () => {
  console.log('用户请求重置上传对话框');
  errorBoundaryKey.value += 1;
  resetDialog();
};
const closeDialog = () => {
  isOpen.value = false;
};
</script>

<template>
  <Dialog
    v-model="isOpen"
    type="modal"
    :prevent-close="isUploading"
    aria-labelledby="upload-dialog-title"
  >
    <DialogBody>
      <div>
        <div class="mb-4 flex items-center justify-between">
          <h2 id="upload-dialog-title" class="text-xl font-semibold">
            新增文件上传
          </h2>

          <Button appearance="subtle" icon-only @click="closeDialog">
            <Close />
          </Button>
        </div>
        <ErrorBoundary
          :key="errorBoundaryKey"
          @error="handleErrorBoundaryError"
          @retry="handleErrorBoundaryRetry"
          @reset="handleErrorBoundaryReset"
        >
          <!-- 标题区域 -->
          <div class="mb-6">
            <div class="mb-2 flex items-center">
              <div
                class="mr-3 flex h-12 w-12 items-center justify-center rounded-lg bg-orange-100 dark:bg-orange-900/30"
              >
                <UploadIcon
                  theme="outline"
                  size="24"
                  fill="currentColor"
                  class="text-orange-600 dark:text-orange-400"
                />
              </div>
              <div>
                <h3 class="text-foreground text-lg font-semibold">文件上传</h3>
                <p class="text-muted-foreground text-sm">
                  选择要上传的文件并添加备注信息
                </p>
              </div>
            </div>
          </div>

          <!-- 主内容区域 -->
          <div class="mb-6 space-y-6">
            <!-- 上部：文件选择和列表区域 -->
            <div class="space-y-4">
              <!-- 文件拖放区域 - 仅在没有文件时显示 -->
              <div v-if="uploadQueue.length === 0">
                <h4 class="text-foreground mb-3 text-sm font-medium">
                  选择文件
                </h4>
                <FileDropZone
                  :max-file-size="100 * 1024 * 1024"
                  :multiple="true"
                  :disabled="isUploading"
                  @files-selected="addFilesToQueue"
                  @error="handleUploadError"
                />
              </div>

              <!-- 文件上传队列 -->
              <FileUploadQueue
                v-if="uploadQueue.length > 0"
                :items="uploadQueue"
                :is-uploading="isUploading"
                :show-upload-info="true"
                @start-upload="startUpload"
                @pause-upload="pauseUpload"
                @remove-item="removeItem"
                @retry-item="retryItem"
                @cancel-item="cancelItem"
                @clear-all="clearAll"
                @reselect-files="reselectFiles"
              />
            </div>

            <!-- 下部：备注信息和操作按钮区域 -->
            <div class="space-y-4">
              <div>
                <h4 class="text-foreground mb-3 text-sm font-medium">
                  备注信息
                </h4>
                <div class="w-full">
                  <TextArea
                    v-model="uploadMessage"
                    :disabled="isUploading"
                    :block="true"
                    :auto-resize="true"
                    placeholder="请输入备注信息..."
                  />
                </div>

                <p class="text-muted-foreground mt-2 text-xs">
                  可在此处添加文件相关说明、用途等信息
                </p>
              </div>

              <!-- 操作按钮区域 -->
              <div
                class="border-border flex items-center justify-end space-x-3 border-t pt-4"
              >
                <Button v-if="uploadQueue.length === 0" @click="handleCancel">
                  取消
                </Button>

                <Button
                  v-if="uploadQueue.length > 0 && !isUploading"
                  appearance="transparent"
                  @click="clearAll"
                  class="text-destructive hover:text-destructive/80 hover:bg-destructive/10"
                >
                  清除
                </Button>

                <Button
                  v-if="uploadQueue.length > 0 && isUploading"
                  appearance="outline"
                  @click="handleCancel"
                  class="text-destructive hover:text-destructive/80 border-destructive/20"
                >
                  取消上传
                </Button>

                <Button
                  appearance="primary"
                  @click="startUpload"
                  :disabled="uploadQueue.length === 0 || isUploading"
                  :loading="isUploading"
                >
                  <div class="flex items-center gap-2">
                    <UploadIcon theme="outline" size="16" fill="currentColor" />
                    开始上传
                  </div>
                </Button>
              </div>
            </div>
          </div>
        </ErrorBoundary>
      </div>
    </DialogBody>
  </Dialog>
</template>

<style scoped>
.upload-dialog {
  @apply bg-card dark:bg-card p-6;

  min-height: 500px;
}

/* 自定义滚动条样式 - 支持暗色模式 */
.max-h-64::-webkit-scrollbar,
.max-h-48::-webkit-scrollbar {
  width: 4px;
}

.max-h-64::-webkit-scrollbar-track,
.max-h-48::-webkit-scrollbar-track {
  @apply bg-secondary;
}

.max-h-64::-webkit-scrollbar-thumb,
.max-h-48::-webkit-scrollbar-thumb {
  @apply bg-border;

  border-radius: 2px;
}

.max-h-64::-webkit-scrollbar-thumb:hover,
.max-h-48::-webkit-scrollbar-thumb:hover {
  @apply bg-primary/70;
}

/* 暗色模式下的特殊样式调整 */

/* @media (prefers-color-scheme: dark) {
  .upload-dialog {
    @apply bg-card;
  }
} */
</style>
